<?php

/**
 * 数据库Pdo_Mysql适配器  
 * 
 * @author edikud
 * @package Db
 * @copyright Copyright (c) 2019 Cola (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class Db_Pdo_Mysql extends Db_Pdo_Abstract
{
    /**
     * 判断适配器是否可用
     *
     * @access public
     * @return boolean
     */
    public static function isAvailable()
    {
        return parent::isAvailable() && in_array('mysql', PDO::getAvailableDrivers());
    }
	
    /**
     * 数据库连接函数
     *
     * @param Container $config 数据库配置
     * @throws Db_Exception
     * @return PDO
     */
    public function connect(Container $config)
    {
        try {
            $this->_pdo = new PDO(!empty($config->dsn) ? $config->dsn :
            "mysql:dbname={$config->dbname};host={$config->host};port={$config->port}", $config->user, $config->password);
            $this->_pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
			$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->_pdo->exec("SET NAMES '{$config->charset}'");
			return $this->_pdo;
        } catch (PDOException $e) {
            throw new Db_Exception($e->getMessage(), $e->getCode());
        }
    }

    /**
     * 清空数据表
     *
     * @param string $table
     * @param mixed $handle 连接对象
     * @return mixed|void
     * @throws Typecho_Db_Exception
     */
    public function truncate($handle)
    {
        $this->query('TRUNCATE TABLE %table%', $handle);
    }
	
    /**
     * 对象引号过滤
     *
     * @access public
     * @param string $string
     * @return string
     */
    public function quoteColumn($string)
    {
        return '`' . $string . '`';
    }

    /**
     * 引号转义函数
     *
     * @param string $string 需要转义的字符串
     * @return string
     */
    public function quoteValue($string)
    {
        return '\'' . str_replace(array('\'', '\\'), array('\'\'', '\\\\'), $string) . '\'';
    }
	
    /**
     * 取出最后一次查询影响的行数
     *
     * @param array $query 查询对象词法数组
     * @param integer $op 数据库操作
     * @return integer
     */
    public function affectedRows($query, $op = Db::WRITE)
    {
		$action = $query->getQuery('action');
		$result = false;

        switch ($action) {
            case 'UPDATE':
                list($sql, $values) = $this->parseUpdate($query);
				break;
            case 'DELETE':
                list($sql, $values) = $this->parseDelete($query);
				break;
            case 'INSERT':
                list($sql, $values) = $this->parseInsert($query);
				break;
            case 'SQL':
                list($sql, $values) = $this->parseSql($query);
				break;
        }
		
		if (isset($sql)) {
			$start_time = microtime(TRUE);
            $stmt = $query->selectDb($op)->prepare($sql);
            $r = $stmt->execute($values);
			
            /**if ($r) {
                $r = $stmt->rowCount();
                $result = $r !== 0 ? true : false;
            }*/
			
			$result = $stmt->rowCount();
			
		    $end_time = microtime(TRUE);
		    Db::debug($sql, $values, ($end_time - $start_time));
		}

        return $result;
    }
	
    /**
     * 取出最后一次插入返回的主键值
     *
     * @param array $query 查询对象词法数组
     * @param integer $op 数据库操作
     * @return integer
     */
    public function lastInsertId($query, $op = Db::WRITE)
    {
		$action = $query->getQuery('action');
		$result = false;

        switch ($action) {
            case 'INSERT':
                list($sql, $values) = $this->parseInsert($query);
				break;
            case 'SQL':
                list($sql, $values) = $this->parseSql($query);
				break;
        }
			
		if (isset($sql)) {
			$start_time = microtime(TRUE);
		    $db = $query->selectDb($op);
            $stmt = $db->prepare($sql);
            $r = $stmt->execute($values);
            if ($r) {
                $r = $stmt->rowCount();
                $result = $r !== 0 ? $db->lastInsertId() : false;
            }
		    $end_time = microtime(TRUE);
		    Db::debug($sql, $values, ($end_time - $start_time));
		}
		
        return $result;
    }
	
    /**
     * 一次取出一行
     *
     * @param array $query 查询对象词法数组
     * @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
     * @param integer $op 数据库操作
     * @return mixed
     */
    public function fetchRow($query, array $filter = NULL, $op = Db::WRITE)
    {
		$action = $query->getQuery('action');
        $result = array();
		
        switch ($action) {
            case 'SELECT':
                list($sql, $values) = $this->parseSelect($query);
				break;
            case 'SQL':
                list($sql, $values) = $this->parseSql($query);
				break;
        }
		
		if (isset($sql)) {
            $start_time = microtime(TRUE);
            $stmt = $query->selectDb($op)->prepare($sql);

            $r = $values ? $stmt->execute($values) : $stmt->execute();
            if ($r) {
				
                /** 取出过滤器 */
                if ($filter) {
                    list($object, $method) = $filter;
                }
				
                $result = ($rows = $stmt->fetch(PDO::FETCH_ASSOC)) ?
                    ($filter ? $object->$method($rows) : $rows) : array();
            }
		    $end_time = microtime(TRUE);
		    Db::debug($sql, $values, ($end_time - $start_time));
		}
        return $result;
    }

    /**
     * 一次取出多行
     *
     * @param array $query 查询对象词法数组
     * @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
     * @param integer $op 数据库操作
     * @return mixed
     */
    public function fetchAll($query, array $filter = NULL, $op = Db::WRITE)
    {
		$action = $query->getQuery('action');
        $result = array();

        switch ($action) {
            case 'SELECT':
                list($sql, $values) = $this->parseSelect($query);
				break;
            case 'SQL':
                list($sql, $values) = $this->parseSql($query);
				break;
        }

		if (isset($sql)) {
			$start_time = microtime(TRUE);
            $stmt = $query->selectDb($op)->prepare($sql);

            $r = $values ? $stmt->execute($values) : $stmt->execute();
            if ($r) {
				
                /** 取出过滤器 */
                if ($filter) {
                    list($object, $method) = $filter;
                }
				
                //取出每一行
                while ($rows = $stmt->fetch(PDO::FETCH_ASSOC)) {
                    //判断是否有过滤器
                    $result[] = $filter ? call_user_func(array(&$object, $method), $rows) : $rows;
                }
            }
		    $end_time = microtime(TRUE);
		    Db::debug($sql, $values, ($end_time - $start_time));
		}
        return $result;
    }
	
    /**
     * 将数据查询的其中一行作为对象取出,其中字段名对应对象属性
     *
     * @param array $query 查询对象词法数组
     * @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
     * @param integer $op 数据库操作
     * @return object
     */
    public function fetchObject($query, array $filter = NULL, $op = Db::WRITE)
    {
		$action = $query->getQuery('action');
        $result = new stdClass();

        switch ($action) {
            case 'SELECT':
                list($sql, $values) = $this->parseSelect($query);
				break;
            case 'SQL':
                list($sql, $values) = $this->parseSql($query);
				break;
        }
		if (isset($sql)) {
			$start_time = microtime(TRUE);
            $stmt = $query->selectDb($op)->prepare($sql);
            $r = $values ? $stmt->execute($values) : $stmt->execute();
            if ($r) {
				
                /** 取出过滤器 */
                if ($filter) {
                    list($object, $method) = $filter;
                }
				
                $result = ($rows = $stmt->fetchObject()) ?
                ($filter ? $object->$method($rows) : $rows) : new stdClass();
            }
			
		    $end_time = microtime(TRUE);
		    Db::debug($sql, $values, ($end_time - $start_time));
		}
        return $result;
    }	
	
}

